using Godot;
using Godot.Collections;
using System;
[GlobalClass]
public partial class Characters : CharacterBody2D,IEntity,ISavable,ILoadable
{
    [Export]
    protected CharacterData _characterData;
    public StateMachine _stateMachine;
    public Movement _movement;
    private BehaviorTree _behaviorTree;
    private Marker2D _hitboxPosition;
    private Area2D _hurtbox;
    private SkillManager _skillManager;
    private Label _nameLabel;
    public Array<string> sightFrom = new Array<string>();
    public string action;
    public Vector2I _moveDirection;
    public Sight _sight;
    private Area2D _floorCheck;
    private AnimationPlay _animationPlay;
    public SaveLoadManager _saveLoadManager;
    public Timer _timer;
    private Area2D sighted;
    [Export]
    public bool safe = false;
    public Vector2 targetPos;
    public CharacterData CharacterData{get => _characterData;}//获取对应的角色数据
    public enum State{
		IDLE,
		RUN,
		ATTACK_LEFT,
		ATTACK_RIGHT,
        SKILL
	}
    
    public virtual void Initialize()
    {
        if(HasNode("BehaviorTree"))
        {
            _behaviorTree = this.GetNode<BehaviorTree>("BehaviorTree");
        }
        _skillManager = GetNode<SkillManager>("SkillManager");
        _hurtbox = GetNode<Area2D>("Hurtbox");
        _hurtbox.AreaEntered += OnHurted;
        _saveLoadManager = GetTree().CurrentScene.GetNode<SaveLoadManager>("SaveLoadManager");
        _movement = GetNode<Movement>("Movement");
		_movement.Initialize();
        InitializeByLoadData();
        _sight = GetNode<Sight>("Sight");
        _sight.Initialize();
        _floorCheck = GetNode<Area2D>("FloorCheck");
        _stateMachine = GetNode<StateMachine>("StateMachine");
        _animationPlay = GetNode<AnimationPlay>("AnimationPlay");
		_animationPlay.Initialize();
        var Game = GetNode<Game>("/root/Game");
        MessageManager messageManager = Game.get_message_manager();
        messageManager.TaskAccept += AcceptTask;
        messageManager.DialogEnd += EndDialog;
        //_stateMachine.current_state = (int)State.IDLE;
        //_timer = this.GetNode<Timer>("Timer");
        _nameLabel = GetNode<Label>("name");
        sighted = GetNode<Area2D>("sighted");
        sighted.AreaEntered += GetBody;
        sighted.AreaExited += RemoveBody;
    }

    public virtual void tickProcess(double delta)
    {
        //_stateMachine._Process(delta);
        if(this.Name != "Player"&&this.Name != "maid")
        {_behaviorTree._Ready();}
        if(_characterData.health <= 0)
        {
            this.QueueFree();
        }
        switch ((State)_stateMachine.current_state)
		{
			case State.IDLE:
			{
				break;
			}
			case State.RUN:
			{
                _movement.Move(_moveDirection,delta);
			    _movement.Update (delta);
				break;
			}
            case State.SKILL:
            {
                break;
            }
		}
    }

    public virtual void HealthDec(int attack)
    {
        this.CharacterData.health -= attack;
        GD.Print(_characterData.name,"shengyuxuelliang",_characterData.health);
    }

    public virtual void AcceptTask(string taskname)
    {
        if(this.CharacterData.tasksList.Count == 0)
        {return;}
        foreach(var tasksList in _characterData.tasksList)
		{
			if(tasksList.Key == taskname&&tasksList.Value)
            {
                _characterData.tasksList[taskname] = false;
                break;
            }
		}
    }

    public void EndDialog(Characters character)
    {
        _characterData.textkey = "text";
    }

    public virtual State GetNextState(int state)
	{
		State _state = (State)state;
        _moveDirection = TargetDirection();
		switch (_state)
		{
			case State.IDLE: //idle
				if(_moveDirection != Vector2I.Zero)
				{
					return State.RUN;
				}
				break;
			case State.RUN: 
				if(_moveDirection == Vector2I.Zero)
				{
					return State.IDLE;
				}
				break;
            case State.SKILL:
                if(!_animationPlay._animated.IsPlaying())
				{
					return State.IDLE;
				}
                break;
			
		}
		return (State)state;
	}

	public virtual void StateChange(int from ,int to)
	{
		State statefrom = (State)from;
		State stateto = (State)to;
		
		switch (stateto)
		{
			case State.IDLE:
			{
                action = "idle";
				break;
			}
			case State.RUN:
			{
				action = "run";
                
				break;
			}
            case State.SKILL:
            {
                action = "attack";
                break;
            }
            case State.ATTACK_LEFT:
            {
                action = "attack";
                break;
            }
		}

        _moveDirection = TargetDirection();
        var movedirection = MoveDirection();
        if(action ==""||action == null)
		{
			action = "idle";
		}
		if(from == to&&stateto == State.SKILL)
		{
			return;
		}
		_animationPlay.Player_Animation(movedirection,action,8.0f);

		if(from != to)
		{
			GD.Print(this.Name,"[",statefrom,"]","==>","[",stateto,"]");
		}
	}

    public double MoveDirection()
    {
        double movedirection = Math.Atan2(_moveDirection.X, _moveDirection.Y);
		movedirection = movedirection / Math.PI * 180;
		if(movedirection<0.0)
		{
			movedirection += 360;
		}
        return movedirection;
    }

    public Vector2I TargetDirection()
    {
        if(targetPos == Vector2.Zero)
        {return Vector2I.Zero;}
        Vector2I dir = Vector2I.Zero;
        dir = (Vector2I)(targetPos - this.GlobalPosition).Sign();
        return dir;

    }

    public double TargetDistance()
    {
        double distance = this.GlobalPosition.DistanceTo(targetPos);

        return distance;
    }

    public virtual void AimTarget()
    {
        Characters targetCharacter = GetTree().CurrentScene.GetNode<Characters>("%"+(_characterData as EnemyData).target);
		var scale = Math.PI*1.5 - targetCharacter._sight.Rotation;
		targetPos = targetCharacter.GlobalPosition; //+ new Vector2((float)Math.Sin(scale)*30, (float)Math.Cos(scale)*30);
    }

    public void OnHurted(Node2D body)
    {
        GD.Print("受击");
        //GD.Print(body.GetParent().Name);
        if(body is Punch&&!(body.GetParent() == this))
        {
            Punch punch = (Punch)body;
            _characterData.health -= punch.attack;
            GD.Print(this.Name,"受到攻击",punch.attack,"剩余",_characterData.health);
        }
    }

    public void GetBody(Node body)
    {
        if (body.Owner is Characters)
        {
            sightFrom.Add(body.Owner.Name);
            GD.Print("被看见",body.Owner.Name);
            try
            {(this._characterData as EnemyData).target = body.Owner.Name;}
            catch(Exception e)
            {
                GD.Print("",e.Message);
            }
            //_behaviorTree._Ready();
        }
        if(body.Owner is Player&&!(this is Player))
        {
            _nameLabel.Text = _characterData.name;
            _nameLabel.Visible = true;
        }
    }

    public void RemoveBody(Node body)
    {
        if(body.Owner is Characters)
        {
            sightFrom.Remove(body.Owner.Name);
        }
        if(body.Owner is Player)
        {
            _nameLabel.Visible = false;
        }
    }


    public bool InitializeByLoadData()
    {
        if(_saveLoadManager.LoadData ==null ||_saveLoadManager.LoadData.Count == 0)
        {
            return false;
        }
        if(this is Player)
        {
            if(!_saveLoadManager.LoadData.ContainsKey("player"))
            {return false;}

            var player = _saveLoadManager.LoadData["player"].AsGodotDictionary<string ,Variant>();

            InitializeByCharacterData(player);
            return true;
        }

        return false;
    }
  

    public virtual Dictionary<string, Variant> GetDataForSave()
    {
        return new Dictionary<string, Variant>
        {
            {"name", _characterData.name},
            {"alive", _characterData.alive},
            {"health", _characterData.health},
            {"MAX_HEALTH", _characterData.MAX_HEALTH},
            {"MAX_SPEED", _characterData.MAX_SPEED},
            {"sight", _characterData.sight},
            {"speed", _characterData.speed},
            {"state", _characterData.state},
            {"attack", _characterData.attack},
            {"ACCELERATION", _characterData.ACCELERATION},
            {"tough", _characterData.tough},
        };
    }

    public virtual Dictionary<string, Variant> GetDataForLoad()
    {
        throw new NotImplementedException();
    }

    protected void InitializeByCharacterData(Dictionary<string , Variant> characterLoadData)
    {
        _characterData.name = characterLoadData["name"].AsString();
        _characterData.alive = characterLoadData["alive"].AsBool();
        _characterData.health = characterLoadData["health"].AsInt32();
        _characterData.MAX_HEALTH = characterLoadData["MAX_HEALTH"].AsInt32();
        _characterData.MAX_SPEED = characterLoadData["MAX_SPEED"].AsInt32();
        _characterData.sight = characterLoadData["sight"].AsInt32();
        _characterData.speed = characterLoadData["speed"].AsInt32();
        _characterData.state = characterLoadData["state"].AsString();
        _characterData.attack = characterLoadData["attack"].AsInt32();
        _characterData.ACCELERATION = characterLoadData["ACCELERATION"].AsInt32();
        _characterData.tough = characterLoadData["tough"].AsInt32();
    }

    public void Update(double delta)
    {
    }
}
